﻿using AutoMapper;
using AutoMapper.Internal.Mappers;
using BingYing.SAAS.SystemModel.Contracts.BaseInfo;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Qianke.Core.Common.Dto;
using System.Linq.Dynamic.Core;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Auditing;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.ObjectMapping;


namespace BingYing.SAAS.SystemModel.Application.BaseInfo
{

    public class SaasBaseService<TEntity, TPrimaryKey, TGetModelOutputDto, TAddAndUpdateInputDto, TGetPageInputDto, TGetPageOutputDto>
        : ApplicationService,
        ISaasBaseService<TPrimaryKey, TGetModelOutputDto, TAddAndUpdateInputDto, TGetPageInputDto, TGetPageOutputDto>
        where TEntity : Entity<TPrimaryKey>
        where TGetPageInputDto : PageDto
    {
        /// <summary>
        /// 仓储
        /// </summary>
        protected readonly IRepository<TEntity, TPrimaryKey> repository;

        /// <summary>
        /// 模型转换器
        /// </summary>
        protected readonly IMapper objectMapper;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="repository"></param>
        /// <param name="objectMapper"></param>
        public SaasBaseService(IRepository<TEntity, TPrimaryKey> repository, IMapper objectMapper)
        {
            this.repository = repository;
            this.objectMapper = objectMapper;
        }

        /// <summary>
        /// 添加或更新前置事件
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        protected virtual Task OnAddOrUpdateBefore(TEntity model) => Task.CompletedTask;

        /// <summary>
        /// //添加或更新后置事件
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        protected virtual Task OnAddOrUpdateAfter(TEntity model) => Task.CompletedTask;

        /// <summary>
        /// 添加或更新数据
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPost]
        public virtual async Task<TGetModelOutputDto> AddOrUpdate(TAddAndUpdateInputDto dto)
        {
            var model = objectMapper.Map<TAddAndUpdateInputDto, TEntity>(dto);
            await OnAddOrUpdateBefore(model);
            if (model.Id.Equals(default(TPrimaryKey)))
                await repository.InsertAsync(model);
            else
                await repository.UpdateAsync(model);
            await OnAddOrUpdateAfter(model);
            return objectMapper.Map<TEntity, TGetModelOutputDto>(model);
        }

        /// <summary>
        /// 根据ID查询详细信息
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        [HttpPost]
        public virtual async Task<TGetModelOutputDto> GetModel(EntityInputDto<TPrimaryKey> entity)
        {
            var model = await repository.FindAsync(entity.Id);
            if (model == null)
                throw new Exception("数据不存在");
            return objectMapper.Map<TEntity, TGetModelOutputDto>(model);
        }

        /// <summary>
        /// 获取分页数据 过滤函数
        /// </summary>
        /// <param name="queryData"></param>
        /// <param name="dto"></param>
        /// <returns></returns>
        protected virtual IQueryable<TEntity> GetPageFilter(IQueryable<TEntity> queryData, TGetPageInputDto dto)
        {
            return queryData;
        }

        /// <summary>
        /// 获取分页数据 排序函数
        /// </summary>
        /// <param name="queryData"></param>
        /// <param name="dto"></param>
        /// <returns></returns>
        protected virtual IQueryable<TEntity> GetPageOrderBy(IQueryable<TEntity> queryData, TGetPageInputDto dto)
        {
            if (typeof(IHasCreationTime).IsAssignableFrom(typeof(TEntity)))
                return queryData.OrderByDescending(u => ((IHasCreationTime)u).CreationTime);
            else
                return queryData.OrderByDescending(u => u.Id);
        }

        /// <summary>
        /// 获取分页数据 输出函数
        /// </summary>
        /// <param name="queryData"></param>
        /// <param name="dto"></param>
        /// <returns></returns>
        protected virtual async Task<PageOutputDto<TGetPageOutputDto>> GetPageOutput(IQueryable<TEntity> queryData, TGetPageInputDto dto)
        {
            var result = new PageOutputDto<TGetPageOutputDto>();
            result.totalCount = await queryData.CountAsync();
            queryData = queryData.PageBy((dto.PageIndex - 1) * dto.PageSize, dto.PageSize);
            var dataList = await queryData.ToListAsync();
            result.data = dataList.Select(u => objectMapper.Map<TEntity, TGetPageOutputDto>(u)).ToList();
            return result;
        }

        /// <summary>
        /// 分页查询数据
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        [HttpPost]

        public virtual async Task<PageOutputDto<TGetPageOutputDto>> GetPage(TGetPageInputDto dto)
        {
            var queryData = await repository.GetQueryableAsync();
            queryData = GetPageFilter(queryData, dto);
            queryData = GetPageOrderBy(queryData, dto);
            queryData.PageResult(dto.PageIndex, dto.PageSize);
            return await GetPageOutput(queryData, dto);
        }

        /// <summary>
        /// 删除前置事件
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        protected virtual Task OnDeleteBefore(TEntity model) => Task.CompletedTask;

        /// <summary>
        /// 删除后置事件
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        protected virtual Task OnDeleteAfter(TEntity model) => Task.CompletedTask;

        /// <summary>
        /// 删除数据
        /// </summary>
        /// <param name="entityDto"></param>
        /// <returns></returns>
        public virtual async Task Delete(EntityInputDto<TPrimaryKey> entityDto)
        {
            var model = await repository.FindAsync(entityDto.Id);
            if (model != null)
            {
                await OnDeleteBefore(model);
                await repository.DeleteAsync(model);
                await OnDeleteAfter(model);
            }
        }
    }
}
